package com.tanhua.dubbo.server.api;

import com.alibaba.dubbo.config.annotation.Service;
import com.mongodb.client.result.DeleteResult;
import com.tanhua.dubbo.server.pojo.*;
import com.tanhua.dubbo.server.vo.PageInfo;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

@Service(version = "1.0.0")
public class QuanZiApiImpl implements QuanZiApi {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private IdService idService;


    /**
     * 发布动态 (1保存发布的动态  2保存到相册表  3他的朋友和用户的时间线表都保存一遍)
     * @param publish 未封装完成的动态对象
     * @return publish.getId()
     */
    @Override
    public String savePublish(Publish publish) {

        // 校验
        if (publish.getUserId() == null) {
            return null;
        }

        try {
            publish.setCreated(System.currentTimeMillis()); //设置创建时间
            publish.setId(ObjectId.get()); //设置id
            //参数: 1类型(动态or视频) 2publish特有的id
            //调用方法获取pid(redis拥有自增的方法)
            publish.setPid(this.idService.createId("publish", publish.getId().toHexString()));
            this.mongoTemplate.save(publish); //保存发布

            Album album = new Album(); // 构建相册对象
            album.setPublishId(publish.getId());
            album.setCreated(System.currentTimeMillis());
            album.setId(ObjectId.get());
            //设置mongoDb中保存的表名为"quanzi_album_" + publish.getUserId()
            //因为每一个用户都有他特有的相册表
            this.mongoTemplate.save(album, "quanzi_album_" + publish.getUserId());

            //写入好友的时间线中
            Criteria criteria = Criteria.where("userId").is(publish.getUserId());
            List<Users> users = this.mongoTemplate.find(Query.query(criteria), Users.class);
            for (Users user : users) {
                TimeLine timeLine = new TimeLine();
                timeLine.setId(ObjectId.get());
                timeLine.setPublishId(publish.getId());
                timeLine.setUserId(user.getUserId());
                timeLine.setDate(System.currentTimeMillis());
                //设置mongoDb中保存的表名为quanzi_time_line_+ user.getFriendId()   代表某个用户的时间表
                this.mongoTemplate.save(timeLine, "quanzi_time_line_" + user.getFriendId());
            }

            //写入自己的时间线中
            TimeLine timeLine = new TimeLine();
            timeLine.setId(ObjectId.get());
            timeLine.setPublishId(publish.getId());
            timeLine.setUserId(publish.getUserId());
            timeLine.setDate(System.currentTimeMillis());
            //设置mongoDb中保存的表名为quanzi_time_line_+ publish.getUserId()   代表自己的的时间表
            this.mongoTemplate.save(timeLine, "quanzi_time_line_" + publish.getUserId());

            return publish.getId().toHexString();
        } catch (Exception e) {
            e.printStackTrace();
            //TODO 出错的事务回滚，MongoDB非集群不支持事务，暂不进行实现
        }

        return null;
    }

    /**
     * 查看好友动态
     * @param pageSize
     * @param page
     * @param userId 当前登录用户id
     * @return pageInfo
     */
    @Override
    public PageInfo<Publish> queryPublishList(Integer pageSize, Integer page, Long userId) {

        //设置查询条件: 1:分页查询   2:根据日期的倒序查询
        Pageable pageable= PageRequest.of(page-1,pageSize, Sort.by(Sort.Order.desc("date")));
        Query query=new Query().with(pageable);

        //设置查询的表名
        String collectionName="quanzi_time_line_"+userId;
        if (userId==null){
            //如果未传入用户id,则表示查询推荐时间线表
            collectionName="quanzi_time_line_recommend";
        }
        //查询时间线表得出所有的信息
        List<TimeLine> timeLines = this.mongoTemplate.find(query, TimeLine.class, collectionName);

        //创建发布表id集合
        List<ObjectId> publishIds=new ArrayList<>();
        for (TimeLine timeLine : timeLines) {
            publishIds.add(timeLine.getPublishId());
        }

        //根据publish id 查询获取publish对象
        //条件: 1发布表的id是集合内   2 根据创建时间的倒序排序
        Query queryPublish=Query.query(Criteria.where("id").in(publishIds)).with(Sort.by(Sort.Order.desc("created")));
        List<Publish> publishes = this.mongoTemplate.find(queryPublish, Publish.class);

        //封装pageInfo对象并返回
        PageInfo<Publish> pageInfo=new PageInfo<>();
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(publishes);
        pageInfo.setPageNum(page);
        pageInfo.setTotal(0);//不提供总数

        return pageInfo;
    }

    /**
     * 点赞
     *
     * @param userId
     * @param publishId
     */
    public boolean saveLikeComment(Long userId, String publishId) {
        //查询mongoDb中点赞数
        Query query = Query.query(Criteria
                .where("publishId").is(new ObjectId(publishId))
                .and("userId").is(userId)
                .and("commentType").is(1));
        long count = this.mongoTemplate.count(query, Comment.class);
        //如果数量不等于0那么代表没数据,否则调用saveComment方法保存数据
        if (count > 0) {
            return false;
        }
        return this.saveComment(userId, publishId, 1, null);
    }

    /**
     * 取消点赞、喜欢等
     *
     * @return
     */
    public boolean removeComment(Long userId, String publishId, Integer commentType) {
        //删除该登录用户对于该发布的点赞数
        Query query = Query.query(Criteria
                .where("publishId").is(new ObjectId(publishId))
                .and("userId").is(userId)
                .and("commentType").is(commentType));
        DeleteResult remove = this.mongoTemplate.remove(query, Comment.class);
        //如果删除成功返回true
        return remove.getDeletedCount() > 0;
    }

    /**
     * 喜欢
     *
     * @param userId 当前登录用户id
     * @param publishId 动态id
     */
    public boolean saveLoveComment(Long userId, String publishId) {
        //3:喜欢
        //从mongoDb中查询该用户对动态的喜欢数
        Query query = Query.query(Criteria
                .where("publishId").is(new ObjectId(publishId))
                .and("userId").is(userId)
                .and("commentType").is(3));
        long count = this.mongoTemplate.count(query, Comment.class);
        //当不为0时代表该用户已点过喜欢,所以返回一个false
        if (count > 0) {
            return false;
        }
        //当为0时将类型3(喜欢)存入mongoDB中
        return this.saveComment(userId, publishId, 3, null);
    }

    /**
     * 将评论的对象保存到mongoDB中
     *
     * @param userId
     * @param publishId
     * @param type
     * @return 保存是否成功
     */
    public boolean saveComment(Long userId, String publishId, Integer type, String content) {
        try {
            //封装Comment对象
            Comment comment = new Comment();
            comment.setId(ObjectId.get());
            comment.setUserId(userId);
            comment.setContent(content);
            comment.setPublishId(new ObjectId(publishId));
            comment.setCommentType(type);
            comment.setCreated(System.currentTimeMillis());

            // 设置发布人的id
            Publish publish = this.mongoTemplate.findById(comment.getPublishId(), Publish.class);
            //当查询的动态publish对象不为空,则代表这是对动态的操作
            if (null != publish) {
                comment.setPublishUserId(publish.getUserId());
            } else {
                Video video = this.mongoTemplate.findById(comment.getPublishId(), Video.class);
                //当查询的视频video对象不为空,则代表这是对视频的操作
                if (null != video) {
                    comment.setPublishUserId(video.getUserId());
                }
            }
            //调用mongoTemplate方法保存到MongoDB中 参数为:comment对象
            this.mongoTemplate.save(comment);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 查询数量(根据评论类型和动态id)
     * @param publishId
     * @param type
     * @return
     */
    @Override
    public Long queryCommentCount(String publishId, Integer type) {
        Query query = Query.query(Criteria.where("publishId").is(new ObjectId(publishId)).and("commentType").is(type));
        return this.mongoTemplate.count(query, Comment.class);
    }


    /**
     * 根据id查询动态
     *
     * @param id
     * @return
     */
    @Override
    public Publish queryPublishById(String id) {
        return this.mongoTemplate.findById(new ObjectId(id), Publish.class);
    }


    /**
     * 查评论
     * @param publishId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<Comment> queryCommentList(String publishId, Integer page, Integer pageSize) {
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.asc("created")));
        Query query = new Query(Criteria
                .where("publishId").is(new ObjectId(publishId))
                .and("commentType").is(2)).with(pageRequest);

        //查询时间线表
        List<Comment> timeLineList = this.mongoTemplate.find(query, Comment.class);

        PageInfo<Comment> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(timeLineList);
        pageInfo.setTotal(0); //不提供总数
        return pageInfo;
    }


    /**
     *查询评论列表
     * @param userId 当前登录的用户id
     * @param type 查询类型 1:点赞
     * @param page 页码
     * @param pageSize 每页显示数量
     * @return PageInfo<Comment>对象
     */
    @Override
    public PageInfo<Comment> queryCommentListByUser(Long userId, Integer type, Integer page, Integer pageSize) {

        //page-1:因为分页从0开始算  条件:1:分页 2:创建时间的倒序排序
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
        //条件: userID=传过来的登录用户id  类型为1=点赞
        Query query = new Query(Criteria
                .where("publishUserId").is(userId)
                .and("commentType").is(type)).with(pageRequest);

        //将符合要求的Comment对象装到list集合中
        List<Comment> commentList = this.mongoTemplate.find(query, Comment.class);

        //将数据封装到pageInfo中返回
        PageInfo<Comment> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(commentList);
        pageInfo.setTotal(0); //不提供总数
        return pageInfo;
    }

    /**
     * 根据pid查询所有的publish
     * @param pidList
     * @return
     */
    @Override
    public List<Publish> queryPublishByPids(List<Long> pidList) {

        Query query=Query.query(Criteria.where("pid").in(pidList)).with(Sort.by(Sort.Order.desc("created")));
        List<Publish> publishList = this.mongoTemplate.find(query, Publish.class);
        return publishList;
    }

    /**
     * 查询相册表(将publish)
     * @param userId 用户id
     * @param page  =页码
     * @param pageSize 每页数量
     * @return 分页结果对象
     */
    @Override
    public PageInfo<Publish> queryAlbumList(Long userId, Integer page, Integer pageSize) {
        PageInfo<Publish> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setTotal(0); //不提供总数

        //条件: 分页   根据创建时间倒序排序
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
        Query query = new Query().with(pageRequest);
        //表名需要拼接
        List<Album> albumList = this.mongoTemplate.find(query, Album.class, "quanzi_album_" + userId);

        //如果没有结果就返回空
        if(CollectionUtils.isEmpty(albumList)){
            return pageInfo;
        }

        //将publishId存入集合
        List<ObjectId> publishIds = new ArrayList<>();
        for (Album album : albumList) {
            publishIds.add(album.getPublishId());
        }

        //根据上面的publishId集合查询发布信息,返回
        Query queryPublish = Query.query(Criteria.where("id").in(publishIds)).with(Sort.by(Sort.Order.desc("created")));
        List<Publish> publishList = this.mongoTemplate.find(queryPublish, Publish.class);

        pageInfo.setRecords(publishList);

        return pageInfo;
    }
}
